function DemoTemplate (config) {
    const q = (v) => document.querySelector(v);
    const expandObj = (t, s) => {
        const isObj = (v) => v && typeof v == "object" && !Array.isArray(v) ? true : false;
        Object.keys(s).forEach((v) => {
            if (isObj(t[v]) && isObj(s[v])) expandObj(t[v], s[v]);
            else if (/^[\$#][\+\*\/\-=][\+\-=] /.test(v)) {
                let n = v.substr(4);
                if ((typeof t[n] == "string" || typeof t[n] == "number") && (typeof s[v] == "string" || typeof s[v] == "number")) {
                    let sFN = function () {
                        t[n] = String(t[n]), s[v] = String(s[v]);
                        if (v.indexOf("+= ") === 1) t[n] += s[v];
                        else if (v.indexOf("=+ ") === 1) t[n] = s[v] + t[n];
                        else if (v.indexOf("=- ") === 1 && t[n].indexOf(s[v]) === 0) t[n] = t[n].substring(s[v].length);
                        else if (v.indexOf("-= ") === 1 && t[n].lastIndexOf(s[v]) + s[v].length === t[n].length) t[n] = t[n].substring(0, t[n].lastIndexOf(s[v]));
                    };
                    if (v.indexOf("$") === 0) sFN();
                    else if (v.indexOf("#") === 0) {
                        let isF = isFinite || Number.isFinite;
                        if (isF(Number(t[n])) && isF(Number(s[v]))) {
                            t[n] = Number(t[n]), s[v] = Number(s[v]);
                            if (v.indexOf("+= ") === 1) t[n] += s[v];
                            else if (v.indexOf("-= ") === 1) t[n] -= s[v];
                            else if (v.indexOf("*= ") === 1) t[n] *= s[v];
                            else if (v.indexOf("/= ") === 1) t[n] /= s[v];
                        } else sFN();
                    };
                }
                else t[n] = s[v];
            }
            else t[v] = s[v];
        });
        return t;
    };
    const e = (type, config) => config ? expandObj(document.createElement(type), config) : document.createElement(type);
    const ap = (dom, node) => {
        let append = (v) => {
            if (typeof node == "string") dom.appendChild(document.createElement(v));
            else if (v instanceof HTMLElement) dom.appendChild(v);
            else if (typeof v == "object") dom = expandObj(dom, v);
        }
        if (Array.isArray(node)) node.forEach((v) => append(v));
        else append(node);
        return dom;
    }
    const copyText = (text) => {
        if (!document.execCommand) return false;
        var currentFocus = document.activeElement, textarea = document.createElement("textarea");
        document.body.appendChild(textarea);
        textarea.value = text;
        textarea.focus();
        if (textarea.setSelectionRange) textarea.setSelectionRange(0, textarea.value.length);
        else textarea.select();
        document.execCommand("copy");
        document.body.removeChild(textarea);
        currentFocus.focus();
        return true;
    };
    const downloadFN = (url, fileName) => {
        if (!fileName) fileName = url;
        var x = new XMLHttpRequest(),
            downEvent = (u) => {
                var a = document.createElement("a");
                a.download = fileName, a.href = u;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
            };
        x.open("GET", url, true);
        x.responseType = "blob";
        x.onload = () => {
            var blob = x.response;
            if ("msSaveOrOpenBlob" in navigator) window.navigator.msSaveOrOpenBlob(blob, fileName);
            else downEvent(URL.createObjectURL(blob));
        };
        x.onerror = () => downEvent(url);
        x.send();
    };
    const { eleName = "DemoTemplate", fontSize = "16px" } = config;
    const cssText = `
        .${eleName} {
            position: relative;
            max-width: 100%;
            padding: 0.5em;
            font-size: ${fontSize};
            overflow: hidden;
            display: flex;
            justify-content: space-between;
            background: #FFF;
            box-shadow: 0 0 6px rgb(150, 150, 150, 0.4);
        }
        .${eleName}-info {
            padding: 1em 2em 1em 3em;
        }
        .${eleName}-info > p {
            font-family: Consolas, "Courier New", Courier, NSimSun, SimSun, monospace;
            margin: 0 0 0.5em 0;
            font-size: 1.75em;
            color: #00008b;
        }
        .${eleName}-info > span {
            margin-left: 2em;
            font-size: 0.95em;
            color: #555555;
        }
        .${eleName}-info > span > b {
            margin: 0 1em 0 -2em;
            color: #423232;
        }
        .${eleName}-info > span > small {
            color: #274fb4;
            cursor: pointer;
        }
        .${eleName}-download {
            max-width: 20em;
            height: 5em;
            margin: 0.5em;
            padding: 0.5em 1.5em;
            transform: translateX(75%);
            border-radius: 1.5em;
            background: linear-gradient(-8deg, #a0dcf0, #ebf5fa);
            box-shadow: 3px 2px 5px rgba(145, 210, 230, 0.5), inset -3px -2px 5px rgba(150, 210, 230, 0.4);
            opacity: 0.8;
            transition: opacity 0.4s, box-shadow 0.4s, transform 0.4s;
            cursor: pointer;
            display: flex;
            align-items: center;
            -webkit-animation: download-into 2.5s;
            animation: download-into 2.5s;
            -webkit-user-select: none;
            -moz-user-select: none;
            user-select: none;
            -webkit-tap-highlight-color: transparent;
        }
        .${eleName}-download:hover {
            transform: translateX(0);
            opacity: 1;
            box-shadow: 3px 2px 6px rgba(145, 210, 230, 0.8), inset -3px -2px 5px rgba(150, 210, 230, 0.5);
        }
        .${eleName}-download > div:first-of-type {
            position: relative;
            width: 4.25em;
            height: 4.25em;
            margin-right: 1.75em;
            border-radius: 50%;
            background-image: linear-gradient(to top, #48c6ef 0%, #6f86d6 100%);
            box-shadow: 0 0 6px rgba(111, 134, 214, 0.8), inset 0 0 12px rgba(111, 134, 214, 0.4);
            flex-shrink: 0;
        }
        .${eleName}-download > div:first-of-type::before, .${eleName}-download > div:first-of-type::after {
            content: " ";
            position: absolute;
            width: 72%;
            height: 76%;
            top: 12%;
            left: 14%;
        }
        .${eleName}-download > div:first-of-type::before {
            background: rgba(255, 255, 255, 0.75);
            clip-path: polygon(10% 16%, 50% 56%, 90% 16%, 50% 33%);
        }
        .${eleName}-download > div:first-of-type::after {
            background: rgba(255, 255, 255, 0.9);
            clip-path: polygon(5% 50%, 50% 95%, 95% 50%, 50% 70%);
        }
        .${eleName}-download > div:last-of-type {
            width: calc(100% - 6em);
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: space-around;
            justify-content: space-evenly;
            white-space: nowrap;
        }
        .${eleName}-download > div:last-of-type > span {
            text-overflow: ellipsis;
            overflow: hidden;
        }
        .${eleName}-download > div:last-of-type > span:last-child {
            font-size: 0.9em;
            color: #333333;
        }
        .${eleName}-download > div:last-of-type > span:first-child {
            font-size: 1.5em;
            letter-spacing: 0.5em;
            color: #222222;
        }
        .${eleName} > div:first-child {
            transform: none;
            animation: none;
        }
        .${eleName}-window, .${eleName}-window > div {
            position: fixed;
        }
        .${eleName}-window {
            width: 100%;
            height: 100%;
            font-size: ${fontSize};
            z-index: 999;
            -webkit-animation: anime_into 0.5s;
            animation: anime_into 0.5s;
            display: none;
        }
        .${eleName}-window-mask {
            width: 100%;
            height: 100%;
            top: 0;
            left: 0;
            background: rgba(128, 128, 128, 0.4);
        }
        .${eleName}-window-word {
            width: 80%;
            height: 65%;
            top: calc(15% - 2em);
            left: calc(10% - 1.5em);
            padding: 1.5em;
            border-radius: 2em;
            background: #FFF;
            box-shadow: 0 0 16px rgba(65, 81, 105, 0.5), inset 0 0 6px rgba(76, 96, 126, 0.2);
            -webkit-animation: anime_into_down 0.75s;
            animation: anime_into_down 0.75s;
        }
        .${eleName}-window-word > div {
            width: 100%;
            height: 100%;
            overflow: auto;
            word-break: break-word;
        }
        .${eleName}-window-button {
            top: 83%;
            left: 50%;
            margin-top: 1em;
            transform: translateX(-50%);
            display: flex;
            justify-content: center;
            -webkit-animation: anime_button_into_down 0.75s;
            animation: anime_button_into_down 0.75s;
        }
        .${eleName}-window input[type="button"] {
            padding: 0.8em 2em;
            margin-right: 2em;
            font-size: 1em;
            border-radius: 2em;
            border: none;
            outline: none;
            cursor: pointer;
            color: #FFF;
            background: linear-gradient(#7ebce9, #2d9ceb);
            box-shadow: 0 1px 6px rgb(45, 156, 235, 0.6), inset 0 0 6px rgba(81, 168, 230, 0.4);
            transition: 0.3s;
            -webkit-tap-highlight-color: transparent;
        }
        .${eleName}-window input[type="button"]:last-of-type {
            margin-right: 0;
        }
        .${eleName}-window input[type="button"]:active {
            color: rgba(255, 255, 255, 0.5);
            background: linear-gradient(#4ea4e0, #6aafe0);
            text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4);
            box-shadow: 0px -1px 5px rgba(63, 137, 190, 0.75), inset 0 0 4px rgba(81, 168, 230, 0.2);
        }
        @media only screen and (min-height: 120vw) {
            .${eleName} {
                flex-direction: column;
                align-items: center;
            }
            .${eleName}-info {
                padding: 1em;
            }
            .${eleName}-download {
                transform: none;
                animation: none;
            }
            .${eleName}-download span:nth-of-type(2) {
                display: none;
            }
        }
        @-webkit-keyframes download-into {
            0% { transform: translateX(0); }
            75% { transform: translateX(0); }
            100% { transform: translateX(75%); }
        }
        @keyframes download-into {
            0% { transform: translateX(0); }
            75% { transform: translateX(0); }
            100% { transform: translateX(75%); }
        }
        @-webkit-keyframes anime_into {
            from { opacity: 0; }
            to { opacity: 1; }
        }
        @keyframes anime_into {
            from { opacity: 0; }
            to { opacity: 1; }
        }
        @-webkit-keyframes anime_into_down {
            from { opacity: 0; transform: translateY(-20%); }
            to { opacity: 1;  transform: translateY(0); }
        }
        @keyframes anime_into_down {
            from { opacity: 0;  transform: translateY(-20%); }
            to { opacity: 1;  transform: translateY(0); }
        }
        @-webkit-keyframes anime_button_into_down {
            from { opacity: 0; transform: translateX(-50%) translateY(-20%); }
            to { opacity: 1;  transform: translateX(-50%) translateY(0); }
        }
        @keyframes anime_button_into_down {
            from { opacity: 0;  transform: translateX(-50%) translateY(-20%); }
            to { opacity: 1;  transform: translateX(-50%) translateY(0); }
        }`;
    let { ele, title, subtitle, resume, detail, fileURL, fileName, fileSize } = config;
    let style = e("style", { className: eleName + "-style", innerHTML: cssText });
        info = e("div", { className: eleName + "-info" }),
        info_title = e("p", { innerText: title != void 0 ? title : "", title: subtitle != void 0 ? subtitle : "" }),
        info_resume = e("span", { innerText: resume != void 0 ? resume : "" }),
        info_subtitle = e("b", { innerText: "【" + subtitle + "】" }),
        info_detailShow = e("small", { innerText: "〖查看更多〗" }),
        download = e("div", { className: eleName + "-download", onclick: () => downloadFN(fileURL, fileName) }),
        download_img = e("div"),
        download_words = e("div"),
        download_word1 = e("span", { innerText: "下载" }),
        download_word2 = e("span", { innerText: (fileName ? fileName + " " : "") + (fileSize ? "(" + fileSize + ")" : "") }),
        windowDIV = e("div", { className: eleName + "-window" }),
        window_mask = e("div", { className: eleName + "-window-mask" }),
        window_word = e("div", { className: eleName + "-window-word" }),
        window_word_content = e("div", { innerText: detail }),
        window_buttons = e("div", { className: eleName + "-window-button" }),
        window_button1 = e("input", { type: "button", value: "不换行" }),
        window_button2 = e("input", { type: "button", value: "复制文本" });

    if (typeof ele == "string") ele = q(ele);
    if (!(ele instanceof HTMLElement)) { ele = e("div"); q("body").insertBefore(ele, q("body").childNodes[0]) }
    ele.className += eleName;
    ap(q("head"), style);
    if (title) ap(info, info_title);
    if (resume || subtitle || detail) ap(info, info_resume);
    if (subtitle) info_resume.insertBefore(info_subtitle, info_resume.childNodes[0]);
    if (detail) {
        info_detailShow.onclick = () => windowDIV.style.display = "block";
        window_mask.onclick = () => windowDIV.style.display = "none";
        window_button1.onclick = () => {
            let c = window_word_content;
            let wrap = c.style.whiteSpace == "nowrap" || window.getComputedStyle(c)["whiteSpace"] == "nowrap";
            c.style.whiteSpace = wrap ? "" : "nowrap";
            window_button1.value = wrap ? "不换行" : "自动换行";
        }
        window_button2.onclick = () => {
            let t = window_button2;
            t.value = copyText(detail) ? "复制成功" : "复制失败";
            clearTimeout(t.setTimeFN);
            t.setTimeFN = setTimeout(function () { t.value = "复制文本" }, 3000);
        }
        ap(info_resume, info_detailShow);
        ap(windowDIV, [window_mask, window_word, window_buttons]);
        ap(window_word, window_word_content);
        ap(window_buttons, [window_button1, window_button2]);
        ap(q("body"), windowDIV);
    }
    ap(ele, info);
    if (fileURL) {
        ap(download, [download_img, download_words]);
        ap(download_words, (fileName || fileSize) ? [download_word1, download_word2] : download_word1);
        ap(ele, download);
    }
}